package de.cau.apo;

import java.io.IOException;

import de.cau.apo.problems.IInstance;
import de.cau.apo.problems.ISolution;

/**
 * This class defines the possible communication methods to the
 * evaluation programm.
 * Look at the different methods to get more details.
 * 
 * @author Marius Richter
 *
 */
public final class CommunicationInterface {

	/**
	 * hide default constructor
	 */
	private CommunicationInterface() {
	}
	
	/**
	 * @return the time left in microseconds or -1 if there is no timelimit
	 * @throws NumberFormatException if the value read from System.in was no number
	 * @throws IOException if reading from System.in failed
	 */
	public static int getTimeLeft() throws NumberFormatException, IOException {
		System.out.println("TIMELEFT");
		System.out.flush();
		String response = readFromSystemIn();
		if (response.equals("NO TIMELIMIT"))
			return -1;
		return Integer.parseInt(response);
	}
	
	/**
	 * 
	 * @return the epsilon that defines the approximation your solution shall yield 
	 * @throws NumberFormatException if the value read from System.in was no float
	 * @throws IOException if reading from System.in failed
	 */
	public static float getEpsilon() throws NumberFormatException, IOException {
		System.out.println("EPSILON");
		System.out.flush();
		String response = readFromSystemIn();
		if (response.equals("NO EPSILON"))
			return -1;
		return Float.parseFloat(response);
	}
	
	/**
	 * @return the path to an instance file that shall be solved
	 * @throws IOException if reading from System.in failed
	 */
	public static String getInstance() throws IOException {
		System.out.println("INSTANCE");
		System.out.flush();
		String instance = readFromSystemIn();
		return instance;
	}
	
	/**
	 * @param time the time in microseconds after the time when you call getInstance() 
	 * @return true if adding the timer was successful, false otherwise
	 * @throws IOException if reading from System.in failed
	 */
	public static boolean addTimer(int time) throws IOException {
		System.out.println("SETTIMER " + time);
		System.out.flush();
		String response = readFromSystemIn();
		return response.equals("OK");
	}
	
	/**
	 * 
	 * @param time the time in microseconds that shall be left before the time limit is exceeded
	 * @return true if adding the timer was successful, false otherwise
	 * @throws IOException if reading from System.in failed
	 */
	public static boolean addTimerEnd(int time) throws IOException {
		System.out.println("SETTIMEREND " + time);
		System.out.flush();
		String response = readFromSystemIn();
		return response.equals("OK");
	}
	
	/**
	 * @param solution the solution that shall be published
	 * @return true if this solution is feasible, false otherwise
	 * @throws IOException if reading from System.in failed
	 */
	public static boolean publishSolution(ISolution<? extends IInstance> solution) throws IOException {
		System.out.println("SOLUTION " + solution.encode());
		System.out.flush();
		String response = readFromSystemIn();
		return (response.equals("OK"));
	}
	
	/**
	 * @return the current string on the system input stream
	 * @throws IOExceptionif an I/O error occurs
	 */
	private static String readFromSystemIn() throws IOException {
		String response = "";
		int nextByte = System.in.read();
		while (nextByte != -1 && nextByte != '\n') {
			response += (char) nextByte;
			nextByte = System.in.read();
		}
		return response;
	}
}
